#ifndef __BINARYREADER__
#define __BINARYREADER__

#include <cstdio>
#include <algorithm>
#include <string>
#include <cstdint>

#ifndef byte
typedef unsigned char byte;
#endif

#include <wx\stream.h>

/// <summary>
/// A wrapper class to read variables from FILE pointers.
/// </summary>
class BinaryReader
{
public:
	wxInputStream *Stream;

	BinaryReader()
	{
	}

	/// <summary>
	/// Initializes a new instance of the <see cref="BinaryReader" /> class.
	/// </summary>
	/// <param name="file">The file.</param>
	BinaryReader(wxInputStream *stream) :
		Stream(stream)
	{
	};

	/// <summary>
	/// Reverses the specified input.
	/// </summary>
	/// <param name="input">The input.</param>
	/// <param name="length">The length.</param>
	static void Reverse(byte *input, size_t length)
	{
		for (size_t i = 0; i < length / 2; ++i)
			std::swap(input[i], input[(length - 1) - i]);
	}

	/// <summary>
	/// Reads a little endian variable.
	/// </summary>
	/// <returns>The little endian variable</returns>
	template<typename T>
	T ReadLittleEndian()
	{
		T val;
		Stream->Read((char*)&val, sizeof(T));
		return val;
	}

	/// <summary>
	/// Reads a big endian variable.
	/// </summary>
	/// <returns>The big endian variable</returns>
	template<typename T>
	T ReadBigEndian()
	{
		T val = ReadLittleEndian<T>();
		Reverse((byte*)&val, sizeof(T));
		return val;
	}

	void ReadBytes(byte *ptr, const size_t &length)
	{
		Stream->Read((char*)ptr, length);
	}

	/// <summary>
	/// Reads a string.
	/// </summary>
	/// <returns>The string.</returns>
	std::string ReadString()
	{
		auto length = ReadBigEndian<uint16_t>(), totalLength = length;
		std::string name;

		if (length != 0)
		{
			name.reserve(length);

			while (true)
			{
				name += ReadLittleEndian<char>();
				length--;

				if (length == 0)
					break;
			}
		}

		return name;
	}
};
#else
class BinaryReader;
#endif